package cn.yuyiling.jelly.sr.service.impl;

import cn.yuyiling.jelly.sr.api.ReviewScheduleService;
import cn.yuyiling.jelly.sr.mongodb.entity.ReviewSchedule;
import cn.yuyiling.jelly.sr.mongodb.repository.ReviewScheduleRepository;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@DubboService
public class ReviewScheduleServiceImpl implements ReviewScheduleService {
    private static final Logger logger = LoggerFactory.getLogger(ReviewScheduleServiceImpl.class);

    @Autowired
    private ReviewScheduleRepository reviewScheduleRepository;

    // 艾宾浩斯复习间隔（单位：小时）
    private static final int[] EBINGHAUS_INTERVAL_HOURS = {
            1,   // 第一次复习：1小时后
            6,   // 第二次复习：6小时后
            24,  // 第三次复习：24小时后
            72,  // 第四次复习：3天后
            168, // 第五次复习：7天后
            672, // 第六次复习：28天后
            1440 // 第七次复习：60天后
    };

    @Override
    public ReviewSchedule createReviewSchedule(String userId, String knowledgePointId) {
        LocalDateTime now = LocalDateTime.now();
        ReviewSchedule schedule = new ReviewSchedule();
        schedule.setUserId(userId);
        schedule.setKnowledgePointId(knowledgePointId);
        schedule.setFirstReviewTime(now);
        schedule.setReviewPlan(calculateReviewPlan(now));
        schedule.setCurrentLevel(0);
        schedule.setMastered(false);
        schedule.setUpdatedAt(now);
        ReviewSchedule reviewSchedule = reviewScheduleRepository.save(schedule);
        return reviewSchedule;
    }

    @Override
    public int getEbbinghausIntervalDays(int reviewCount) {
        if (reviewCount < 0 || reviewCount >= EBINGHAUS_INTERVAL_HOURS.length) {
            throw new IllegalArgumentException("Invalid review count");
        }
        // 将小时转换为天数（向上取整）
        return (int) Math.ceil(EBINGHAUS_INTERVAL_HOURS[reviewCount] / 24.0);
    }

    @Override
    public ReviewSchedule updateReviewRecord(String scheduleId, LocalDateTime actualReviewTime) {
        Optional<ReviewSchedule> schedule_Optional = reviewScheduleRepository.findById(scheduleId);
        ReviewSchedule schedule = schedule_Optional.get();
        if (schedule != null) {
            // 确保实际复习时间不早于计划时间
            if (actualReviewTime.isAfter(schedule.getReviewPlan().get(schedule.getCurrentLevel()))) {
                if (schedule.getActualReviews() == null) {
                    schedule.setActualReviews(new ArrayList<>());
                }
                schedule.getActualReviews().add(actualReviewTime);

                // 如果还有更多复习计划，则增加当前级别
                if (schedule.getCurrentLevel() < schedule.getReviewPlan().size() - 1) {
                    schedule.setCurrentLevel(schedule.getCurrentLevel() + 1);
                }

                // 如果完成所有复习计划，标记为已掌握
                if (schedule.getCurrentLevel() >= EBINGHAUS_INTERVAL_HOURS.length - 1) {
                    schedule.setMastered(true);
                }

                schedule.setUpdatedAt(LocalDateTime.now());
                return reviewScheduleRepository.save(schedule);
            } else {
                logger.warn("Actual review time cannot be earlier than scheduled time");
                return null;
            }
        }
        return null;
    }

    @Override
    public List<ReviewSchedule> getReviewSchedulesByUser(String userId) {

        return reviewScheduleRepository.findByUserId(userId);
    }

    @Override
    public List<ReviewSchedule> getDueReviews(String userId, LocalDateTime checkTime) {
        List<ReviewSchedule> allSchedules = reviewScheduleRepository.findByUserId(userId);
        List<ReviewSchedule> dueSchedules = new ArrayList<>();

        for (ReviewSchedule schedule : allSchedules) {
            if (!schedule.isMastered() &&
                    schedule.getCurrentLevel() < schedule.getReviewPlan().size()) {

                LocalDateTime nextReviewTime = schedule.getReviewPlan().get(schedule.getCurrentLevel());

                if (!nextReviewTime.isAfter(checkTime)) {
                    dueSchedules.add(schedule);
                }
            }
        }

        return dueSchedules;
    }

    @Override
    public List<LocalDateTime> calculateReviewPlan(LocalDateTime startTime) {
        List<LocalDateTime> plan = new ArrayList<>();
        for (int i = 0; i < EBINGHAUS_INTERVAL_HOURS.length; i++) {
            plan.add(startTime.plus(EBINGHAUS_INTERVAL_HOURS[i], ChronoUnit.HOURS));
        }
        return plan;
    }
}